<template>
  <div class="typing-effect">
    <div class="typing-content" v-html="displayedText"></div>
    <div v-if="isTyping" class="typing-cursor">|</div>
  </div>
</template>

<script setup lang="ts">
import { ref, watch, onMounted, onUnmounted } from 'vue'

interface Props {
  text: string
  speed?: number
  autoStart?: boolean
}

const props = withDefaults(defineProps<Props>(), {
  speed: 30,
  autoStart: true
})

const emit = defineEmits<{
  complete: []
  update: [text: string]
}>()

const displayedText = ref('')
const isTyping = ref(false)
let typingTimer: ReturnType<typeof setInterval> | null = null
let currentIndex = 0

const startTyping = () => {
  if (typingTimer) {
    clearInterval(typingTimer)
  }
  
  displayedText.value = ''
  currentIndex = 0
  isTyping.value = true
  
  typingTimer = setInterval(() => {
    if (currentIndex < props.text.length) {
      displayedText.value = props.text.slice(0, currentIndex + 1)
      currentIndex++
      emit('update', displayedText.value)
    } else {
      isTyping.value = false
      clearInterval(typingTimer!)
      typingTimer = null
      emit('complete')
    }
  }, props.speed)
}

const stopTyping = () => {
  if (typingTimer) {
    clearInterval(typingTimer)
    typingTimer = null
  }
  isTyping.value = false
  displayedText.value = props.text
  emit('complete')
}

const reset = () => {
  stopTyping()
  displayedText.value = ''
  currentIndex = 0
}

watch(() => props.text, (newText) => {
  if (newText && props.autoStart) {
    startTyping()
  }
}, { immediate: true })

onMounted(() => {
  if (props.text && props.autoStart) {
    startTyping()
  }
})

onUnmounted(() => {
  stopTyping()
})

defineExpose({
  startTyping,
  stopTyping,
  reset
})
</script>

<style lang="scss" scoped>
.typing-effect {
  display: flex;
  align-items: flex-start;
  
  .typing-content {
    flex: 1;
    line-height: 1.6;
    color: #333;
  }
  
  .typing-cursor {
    color: #1890ff;
    font-weight: bold;
    animation: blink 1s infinite;
    margin-left: 2px;
  }
}

@keyframes blink {
  0%, 50% { opacity: 1; }
  51%, 100% { opacity: 0; }
}
</style>
